home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / cps / closure.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  47.1 KB  |  1,395 lines

  1. (****************************************************************************
  2.  *                                                                          *
  3.  * NOTE: debugging code has been commented out as follows:                  *
  4.  *           (***> ...code... <***)                                         *
  5.  *                                                                          *
  6.  ****************************************************************************)
  7.  
  8. signature CLOSURE =
  9.   sig
  10.     val closeCPS : CPS.function -> CPS.function
  11.   end
  12.  
  13. functor Closure(val maxfree : int) : CLOSURE =
  14. struct
  15.  
  16. open CPS Access AllocProf SortedList
  17. structure CGoptions = System.Control.CG
  18.  
  19. val OFFp0 = OFFp 0
  20.  
  21. (**********************************************************************
  22.  * Miscellaneous utility functions.                                   *
  23.  *                                                                    *
  24.  * NOTE: An important property of partition and sublist is that they  *
  25.  *  take sorted lists to sorted lists.                                *
  26.  **********************************************************************)
  27. fun partition f l = fold (fn (e,(a,b)) => if f e then (e::a,b) else (a,e::b))
  28.              l (nil,nil)
  29.  
  30. fun sublist test =
  31.   let fun subl(a::r) = if test a then a::(subl r) else subl r
  32.         | subl nil = nil
  33.   in  subl
  34.   end
  35.  
  36. fun formap f =
  37.   let fun iter(nil,_) = nil
  38.     | iter(hd::tl,i) = f(hd,i)::iter(tl,i+1)
  39.   in  iter o (fn l => (l,0))
  40.   end
  41.  
  42. val error = ErrorMsg.impossible
  43.  
  44. local val save = (!saveLvarNames before saveLvarNames := true)
  45.       val closure = namedLvar(Symbol.varSymbol "closure")
  46. in    val closureLvar = (saveLvarNames := save; fn () => dupLvar closure)
  47. end
  48.  
  49.  
  50. (**********************************************************************
  51.  * Static environments.                                               *
  52.  **********************************************************************)
  53. datatype closureRep = CR of int * {functions : (lvar * lvar) list,
  54.                    values : lvar list,
  55.                    closures : (lvar * closureRep) list,
  56.                    stamp : lvar}
  57. datatype object = Value
  58.         | Function of {label:lvar,free:lvar list}
  59.         | Closure of closureRep
  60.                 | Callee of value * value list
  61. datatype access = Direct
  62.         | Path of (lvar * accesspath)
  63.  
  64. abstype env = Env of lvar list *                    (* values *)
  65.                  (lvar * closureRep) list *     (* closures *)
  66.                      object Intmap.intmap           (* what map *)
  67. with
  68. exception NotBound
  69. fun emptyEnv() = Env(nil,nil,Intmap.new(32,NotBound))
  70.  
  71. (* Update an environment *)
  72. fun augment(m as (v,obj),e as Env(valueL,closureL,whatMap)) =
  73.       (Intmap.add whatMap m;
  74.        case obj
  75.          of Value => Env(v::valueL,closureL,whatMap)
  76.           | Closure cr => Env(valueL,(v,cr)::closureL,whatMap)
  77.           | _ => e)
  78. fun augmentV(v,Env(valueL,closureL,whatMap)) =
  79.       (Intmap.add whatMap(v,Value);
  80.        Env(v::valueL,closureL,whatMap))
  81. fun addCallee(Env(_,_,whatMap),(v,c)) = Intmap.add whatMap (v,Callee c)
  82.  
  83. (* Return the immediately enclosing closure, if any.  This is a hack. *)
  84. fun getClosure (Env(_,closureL,_)) =
  85.   let fun getc ([z]) = SOME z
  86.     | getc (_::tl) = getc tl
  87.     | getc nil = NONE
  88.   in  getc closureL
  89.   end
  90.  
  91. (* Return all the closures currently in the environment. *)
  92. fun getClosures (Env(_,closureL,_)) = closureL
  93.  
  94.  
  95.  
  96. (**********************************************************************
  97.  * Environment printing, for debugging.                               *
  98.  **********************************************************************)
  99. val pr = System.Print.say
  100. val vp = pr o Access.lvarName
  101. fun plist p l = (app (fn v => (pr " "; p v)) l; pr "\n")
  102. val ilist = plist vp
  103. fun sayv(VAR v) = pr(Access.lvarName v)
  104.   | sayv(LABEL v) = (pr "(L)"; pr(Access.lvarName v))
  105.   | sayv(INT i) = (pr "(I)"; pr(makestring i))
  106.   | sayv(REAL r) = pr r
  107.   | sayv(STRING s) = (pr "\""; pr s; pr "\"")
  108.   | sayv(OBJECT _) = pr "**OBJECT**"
  109. val vallist = plist sayv
  110.  
  111. fun printEnv(Env(valueL,closureL,whatMap)) =
  112.   let fun ip i = pr(Integer.makestring i)
  113.       val tlist = plist (fn (a,b) => (vp a; pr "/"; sayv(LABEL b)))
  114.       fun fp(v,Function{label,free}) =
  115.     (vp v; pr "/known "; sayv(LABEL label); pr " -"; ilist free)
  116.         | fp _ = ()
  117.       fun cp (v,Callee(v',vl)) =
  118.     (vp v; pr "/callee "; sayv v'; pr " -"; vallist vl)
  119.         | cp _ = ()
  120.       fun p(indent,l,seen) =
  121.     let fun c(v,CR(offset,{functions,values,closures,stamp})) =
  122.           (indent(); pr "Closure "; vp v; pr "/"; ip stamp;
  123.            pr " @"; ip offset;
  124.            if member seen stamp
  125.            then pr "(seen)\n"
  126.            else (pr ":\n";
  127.              case functions
  128.                of nil => ()
  129.                 | _ => (indent(); pr "  Funs:"; tlist functions);
  130.              case values
  131.                of nil => ()
  132.                 | _ => (indent(); pr "  Vals:"; ilist values);
  133.              p(fn() => (indent();pr "  "),closures,enter(stamp,seen))))
  134.     in  app c l
  135.     end
  136.   in  pr "Values:"; ilist valueL;
  137.       pr "Closures:\n"; p(fn () => (),closureL,nil);
  138.       pr "Known function mapping:\n"; Intmap.app fp whatMap;
  139.       pr "Callee-save continuation mapping:\n";
  140.       Intmap.app cp whatMap
  141.   end
  142.  
  143.  
  144. exception Lookup of lvar * env
  145. (************************************************************************
  146.  * whatIs: return type of object bound to an lvar in an environment.    *
  147.  ************************************************************************)
  148. fun whatIs(env as Env(_,_,whatMap),v) =
  149.   Intmap.map whatMap v
  150.     handle NotBound => raise Lookup(v,env)
  151.  
  152. (************************************************************************
  153.  * whereIs: find the access path to a value in an environment.          *
  154.  ************************************************************************)
  155. fun whereIs(env as Env(valueL,closureL,whatMap),target) =
  156.   let fun bfs(nil,nil) = raise Lookup(target,env)
  157.     | bfs(nil,next) = bfs(next,nil)
  158.     | bfs((h,CR(offset,{functions,values,closures,stamp}))::m,next) =
  159.             let fun cls(nil,i,next) = bfs(m,next)
  160.           | cls((v,cr)::t,i,next) =
  161.             if target=v
  162.             then h(SELp(i-offset,OFFp 0))
  163.             else cls(t,i+1,
  164.                  (fn p => h(SELp(i-offset,p)),cr)::next)
  165.         fun vls(nil,i) = cls(closures,i,next)
  166.           | vls(v::t,i) =
  167.             if target=v
  168.             then h(SELp(i-offset,OFFp 0))
  169.             else vls(t,i+1)
  170.         fun fns(nil,i) = vls(values,i)
  171.           | fns((v,l)::t,i) =
  172.             if target=v
  173.             then h(OFFp(i-offset)) (* possible OFFp 0 *)
  174.             else fns(t,i+1)
  175.         in  if target=stamp
  176.         then h(OFFp(~offset)) (* possible OFFp 0 *)
  177.         else fns(functions,0)
  178.         end
  179.       fun search closures =
  180.     let val (v,p) = bfs(map (fn (v,cr) => ((fn p => (v,p)),
  181.                            cr)) closures,
  182.                 nil)
  183.     in  Path(v,p)
  184.     end
  185.       fun lookC ((v,_)::tl) =
  186.         if target=v then Direct else lookC tl
  187.     | lookC nil = search closureL
  188.       fun lookV (v::tl) =
  189.         if target=v then Direct else lookV tl
  190.     | lookV nil = search closureL
  191.   in  case whatIs(env,target)
  192.     of Function _ => Direct
  193.      | Callee _ => Direct
  194.      | Closure _ => lookC closureL
  195.      | Value => lookV valueL
  196.   end
  197.  
  198. end (* abstype env *)
  199.  
  200.  
  201. (* return the ith object of a closure *)
  202. fun select(i,CR(offset,{functions,values,closures,...})) =
  203.   let val index = offset + i - length functions
  204.       val vlen = length values
  205.   in  if index >= vlen
  206.       then (Closure o #2 o nth)(closures,index - vlen)
  207.       handle Nth => error "bad select in cps/closure"
  208.       else if index < 0 then error "bad select' in cps/closure"
  209.       else Value
  210.   end 
  211.  
  212. (* Bind the offset of a closure to a variable in an environment *)
  213. fun offset(i,CR(offset,x),v,env) =
  214.   augment((v,Closure(CR(offset+i,x))),env)
  215.  
  216. (* Perhaps we should change the representation of closures
  217.    to make this faster. *)
  218. fun inClosure (c,CR(_,{functions,values,closures,stamp})) v =
  219.   (v=c
  220.    orelse v=stamp
  221.    orelse exists (fn (w,_) => v=w) functions
  222.    orelse exists (fn w => v=w) values
  223.    orelse exists (fn z => inClosure z v) closures)
  224.  
  225.  
  226.  
  227. (****************************************************************************
  228.  * "Alpha conversion": the closure converter introduces duplicate bindings  *
  229.  * at function arguments (the free variables of known functions) and at     *
  230.  * SELECT's and OFFSET's from closures.  This function restores unique      *
  231.  * bindings, and also eliminates OFFSET's of 0 (which are introduced as     *
  232.  * a side effect of trying to improve lazy display).  It assumes that a     *
  233.  * FIX has no free variables.                                               *
  234.  ****************************************************************************)
  235. fun unrebind ce =
  236. let fun rename rebind(VAR v) =
  237.           let fun f nil = VAR v
  238.             | f ((w:int,v')::t) = if v=w then v' else f t
  239.           in  f rebind
  240.           end
  241.       | rename _ x = x
  242.     fun f (l,args,b) =
  243.       let val (args',rebind') = fold (fn(v,(args',rebind')) =>
  244.                     let val v' = dupLvar v
  245.                     in  (v'::args',(v, VAR v')::rebind')
  246.                     end)
  247.                      args (nil,nil)
  248.       in  (l,args',g rebind' b)
  249.       end
  250.     and g (rebind: (lvar * value) list) =
  251.       let val rename = rename rebind
  252.       val rec h =
  253.            fn RECORD(kind,vl,w,e) =>
  254.             RECORD(kind,map (fn(v,p) => (rename v,p)) vl,w,h e)
  255.         | OFFSET(0,v,w,e) => g ((w,rename v)::rebind) e
  256.         | OFFSET(i,v,w,e) =>
  257.             let val w' = dupLvar w
  258.             in  OFFSET(i,rename v,w',g ((w, VAR w')::rebind) e)
  259.             end
  260. (*        | SELECT(i,v,w,e as APP(VAR x, args)) =>
  261.             let val w' = dupLvar w
  262.             in  if w=x
  263.                 then SELECT(i,rename v,w',APP(VAR w',map rename args))
  264.                 else SELECT(i,rename v,w',g((w,VAR w')::rebind) e)
  265.             end
  266. *)        | SELECT(i,v,w,e) =>
  267.             let val w' = dupLvar w
  268.             in  SELECT(i,rename v,w',g((w, VAR w')::rebind) e)
  269.             end
  270.         | APP(f,vl) => APP(rename f,map rename vl)
  271.         | FIX(l,e) => FIX(map f l,h e)
  272.         | SWITCH(v,c,el) => SWITCH(rename v,c,map h el)
  273.         | BRANCH(i,vl,c,e1,e2) => BRANCH(i,map rename vl,c, h e1, h e2)
  274.         | SETTER(i,vl,e) => SETTER(i,map rename vl,h e)
  275.         | LOOKER(i,vl,w,e) => LOOKER(i,map rename vl,w,h e)
  276.         | ARITH(i,vl,w,e) => ARITH(i,map rename vl,w,h e)
  277.         | PURE(i,vl,w,e) => PURE(i,map rename vl,w,h e)
  278.       in  h 
  279.       end
  280. in  g nil ce
  281. end
  282.  
  283.  
  284. (****************************************************************************
  285.  * closeCallGraph: compute the transitive closure of the call graph of a    *
  286.  * set of (possibly recursive) functions.                                   *
  287.  ****************************************************************************)
  288. type info = {v:lvar,args:lvar list,body:cexp,other:lvar list}
  289. fun closeCallGraph g =
  290.   let fun getNeighbors l =
  291.         fold (fn (({v,...}:info,_,nbrs),n) =>
  292.           if member l v then merge(nbrs,n)
  293.           else n) g l
  294.       fun f ((x,len,nbrs),(l,change)) =
  295.       let val nbrs' = getNeighbors nbrs
  296.           val len' = length nbrs'
  297.       in  ((x,len',nbrs')::l,change orelse len<>len')
  298.       end
  299.       val (g',change) = fold f g (nil,false)
  300.   in  if change then closeCallGraph g' else g'
  301.   end
  302.  
  303.  
  304. (**********************************************************************
  305.  * Simple closure strategies.                                         *
  306.  **********************************************************************)
  307. local
  308. fun flat(env,free) =
  309.  fold (fn (v,(vls,cls)) =>
  310.         let val obj = whatIs(env,v)
  311.     in  case obj
  312.               of Value => (v::vls,cls)
  313.                | Closure cr => (vls,(v,cr)::cls)
  314.            | _ => error "unexpected vc in cps/closure.sml"
  315.     end) free (nil,nil)
  316. fun link(env,free) =
  317.   case getClosure(env)
  318.     of NONE => flat(env,free)
  319.      | SOME z =>
  320.          let val notIn = sublist (not o (inClosure z)) free
  321.          val (values,closures) = flat(env,notIn)
  322.      in  if length(notIn) = length(free) (* Does adding the
  323.                                                 closure help? *)
  324.          then (values,closures)          (* NO *)
  325.          else (values,z::closures)       (* YES *)
  326.      end
  327. in
  328. fun closureStrategy(functions,free,env) =
  329.   let val (values,closures) =
  330.         case !CGoptions.closureStrategy
  331.       of 3 => link(env,free)
  332.        | 2 => link(env,free)
  333.        | _ => flat(env,free)
  334.       val cname = closureLvar()
  335.   in  (cname,{cname=cname,
  336.              cr=CR(0,{functions=functions,
  337.                values=values,closures=closures,stamp=cname}),
  338.           contents=(map (LABEL o #2) functions)
  339.                    @ (map VAR values)
  340.                    @ (map (VAR o #1) closures)})
  341.   end
  342. end (* local *)
  343.  
  344.  
  345. (**********************************************************************
  346.  * sameClosureOpt: if two free variables are functions from the same  *
  347.  * closure, just one of them is sufficient to access both.            *
  348.  **********************************************************************) 
  349. fun sameClosureOpt(free,env) =
  350. case !CGoptions.closureStrategy
  351.   of 0 => free (* flat without aliasing *)
  352.    | 2 => free (* linked without aliasing *)
  353.    | _ => (* all others have aliasing *)
  354.   let val mapping = map (fn v => let val obj = whatIs(env,v)
  355.                  in  (v,obj)
  356.                  end) free
  357.       fun uniq ((hd as (v,Closure(CR(_,{stamp,...}))))::tl) =
  358.     let val m' = uniq tl
  359.     in  if exists (fn (_,Closure(CR(_,{stamp=stamp',...}))) => stamp=stamp'
  360.             | _ => false) m'
  361.         then m' else hd::m'
  362.     end
  363.     | uniq (hd::tl) = hd::uniq tl
  364.     | uniq nil = nil
  365.   in  map #1 (uniq mapping)
  366.   end
  367.  
  368.  
  369. local
  370. fun follow rootvar =
  371.   let val rec follow0 =
  372.     fn (v,OFFp off,h) =>
  373.         h o (fn ce => OFFSET(off,VAR v,rootvar,ce))
  374.      | (v,SELp(i,OFFp 0),h) =>
  375.         h o (fn ce => SELECT(i,VAR v,rootvar,ce))
  376.      | (v,SELp(i,p),h) =>
  377.         let val w = mkLvar()
  378.         in  follow0(w,p,h o (fn ce => SELECT(i,VAR v, w, ce)))
  379.         end handle Bind => error "follow in closure"
  380.   in  follow0
  381.   end
  382. in
  383. (****************************************************************************
  384.  * fixAccess: find the access path to a variable.  A header to select the   *
  385.  * variable from the environment is returned, along with a new environment  *
  386.  * that reflects the actions of the header (this last implements a "lazy    *
  387.  * display").  fixAccess actually causes rebindings -- the variable         *
  388.  * requested is rebound if it is not immediately available in the           *
  389.  * environment.                                                             *
  390.  ****************************************************************************)
  391. fun fixAccess(args,env) =
  392. let
  393. fun access(VAR rootvar,(env,header)) =
  394.   let val what = whatIs(env,rootvar)
  395.   in  case what
  396.     of Callee _ => error "Callee in fixAccess"
  397.      | Function _ => error "Function in fixAccess"
  398.      | _ => ();
  399.       case whereIs(env,rootvar)
  400.     of Direct => (env,header)
  401.      | Path(start,path) =>
  402.         let val header = follow rootvar (start,path,header)
  403.         val env = augment((rootvar,what),env)
  404.         in  if not(!CGoptions.allocprof) then (env,header)
  405.         else (env,header o profLinks(lenp path))
  406.         end
  407.   end
  408.   | access(_, y) = y
  409. in  fold access args (env,fn x => x)
  410. end
  411.  
  412. fun fixArgs(args,env) =
  413.   let fun fixArgs0 (nil,env,h) = (nil,env,h)
  414.     | fixArgs0 (hd::tl,env,h) =
  415.             (case hd
  416.            of VAR rootvar =>
  417.           let val what = whatIs(env,rootvar)
  418.           in  case what
  419.             of Callee(label,extra) =>
  420.                  let val args' = (label::extra)@tl
  421.                  val (env,h') = fixAccess(args',env)
  422.                  in  (args',env,h o h')
  423.                  end
  424.              | Function _ => error "Function in fixArgs"
  425.              | _ =>
  426.               (case whereIs(env,rootvar)
  427.                  of Direct =>
  428.                  let val (args',env,h) = fixArgs0(tl,env,h)
  429.                  in  (hd::args',env,h)
  430.                  end
  431.                 | Path(start,path) =>
  432.                   let val h = follow rootvar
  433.                                  (start,path,h)
  434.                       val env = augment((rootvar,what),env)
  435.                       val (args',env,h) = fixArgs0(tl,env,h)
  436.                   in  if not(!CGoptions.allocprof)
  437.                       then (hd::args',env,h)
  438.                       else (hd::args',env,
  439.                         h o profLinks(lenp path))
  440.                   end)
  441.           end
  442.                 | _ => let val (args',env,h) = fixArgs0(tl,env,h)
  443.                in  (hd::args',env,h)
  444.                end)
  445.    in  fixArgs0(args,env,fn x => x)
  446.    end (* fixArgs *)
  447. end (* local *)
  448.  
  449.  
  450.  
  451. (****************************************************************************
  452.  * recordEl: Find the complete access paths for elements of a record.       *
  453.  * Return a header for profiling purposes if needed.                        *
  454.  ****************************************************************************)
  455. fun recordEl(l,env) =
  456. if not(!CGoptions.allocprof)
  457. then (map (fn (VAR v,p) => 
  458.                (case whereIs(env,v)
  459.            of Direct => (VAR v,p)
  460.             | Path(start,path) => (VAR start, combinepaths(path,p)))
  461.             | vp => vp)
  462.           l,
  463.       fn x => x)
  464. else
  465. let val (rl,cl) = 
  466.       fold (fn ((VAR v,p),(l,cl)) =>
  467.              let val (m,cost) =
  468.                        case whereIs(env,v)
  469.              of Direct => ((VAR v,p),0)
  470.               | Path(start,path) =>
  471.                   ((VAR start, combinepaths(path,p)),
  472.                    lenp path)
  473.          in  (m::l,cost::cl)
  474.          end
  475.           | (m,(l,cl)) => (m::l,0::cl))
  476.         l (nil,nil)
  477. in  (rl,profRecLinks cl)
  478. end
  479.  
  480.  
  481.  
  482. (****************************************************************************
  483.  * freeAnalysis: Take a free variable list and:                             *
  484.  * (1) replace knownfuncs by their free variables;                          *
  485.  * (2) replace callee-save continuations by their extra arguments.          *
  486.  ****************************************************************************)
  487. local
  488. fun clean l = 
  489. let fun vars(l, VAR x :: rest) = vars(x::l, rest)
  490.       | vars(l, _::rest) = vars(l,rest)
  491.       | vars(l, nil) = l
  492.  in vars(nil,l)
  493. end
  494. in
  495. fun freeAnalysis(free,env) =
  496.   fold (fn (v,l) =>
  497.       case whatIs(env,v)
  498.           of Callee(VAR v',extra) => (** outside case **)
  499.                                    (** the clean is unnecessary **)
  500.              merge(l,enter(v',uniq(clean extra)))
  501.            | Callee(LABEL _,extra) => (** inside case **)
  502.              merge(l,uniq(clean extra))
  503.            | Function{free,...} => merge(free,l)
  504.            | _ => enter(v,l))
  505.     free nil
  506. end
  507.  
  508.  
  509.  
  510. (**********************************************************************
  511.  * closeCPS: MAIN FUNCTION                                            *
  512.  **********************************************************************)
  513. fun closeCPS(f,vl,ce) =
  514. let
  515.  
  516. val baseEnv = emptyEnv()
  517.  
  518. val numCSregs = !System.Control.CG.calleesaves
  519. (*
  520. val numCSregs = if (numCSregs = 1 orelse numCSregs < 0)
  521.         then 2 else numCSregs
  522. *)
  523.  
  524. local
  525. val ((f,vl,ce),iscont0,ebinfo0) =
  526.  (case numCSregs
  527.     of 0 => ((f,vl,ce),fn _ => false, 
  528.               fn _ => error "check EBinfo when callee=0 in closure.sml")
  529.      | _ => ContMap.contmap(f,vl,ce))
  530.  
  531. val (freevars,isEscape,isKnown) = FreeMap.freemapClose ce
  532. in    
  533. (** A continuation will be known if the function that it gets
  534.     passed to is inlined.  If so, we just treat it as a regular
  535.     known function. **)
  536. fun isCallee v = (iscont0 v) andalso (not(isKnown v))
  537. val ebinfo = ebinfo0
  538. val (f,vl,ce,freevars,isEscape) = (f,vl,ce,freevars,isEscape)
  539. end (* local *)
  540.  
  541.  
  542. val extraConst =
  543.   let fun ec(0) = nil
  544.     | ec(k) = (INT 0)::(ec(k-1))
  545.   in  ec(numCSregs)
  546.   end
  547.  
  548. (***********************************************************************
  549.  * addExtra: look at the formal arguments of a function, and replace   *
  550.  * parameters to be treated as callee-save continuations by new        *
  551.  * parameters for the continuation and its extra arguments.            *
  552.  ***********************************************************************)
  553. local
  554. fun extraLvar(0) = nil
  555.   | extraLvar(k) =  mkLvar()::extraLvar(k-1)
  556. in
  557. fun addExtra(args) =
  558.   fold (fn (a,(al,el)) =>
  559.      if isCallee a
  560.      then let val a' = dupLvar a
  561.           val el' = extraLvar(numCSregs)
  562.           in  if not(null el)
  563.              (* A function can have 1 or 0 continuation
  564.                 arguments -- 0 if it is a continuation. *)
  565.           then error "closure/addExtra: >1 continuation"
  566.           else (addCallee(baseEnv,(a,(VAR a',map VAR el')));
  567.             (a'::(el'@al),el'))
  568.           end
  569.      else  (a::al,el)) args (nil,nil)
  570. end (* local *)
  571.  
  572. fun addinc(c,label,extra) = addCallee(baseEnv,(c,(LABEL label,extra)))
  573.  
  574. (***>
  575. val alphac = System.Control.CG.alphac
  576. val unrebind = fn x => if !alphac then unrebind x else x
  577. <***)
  578.  
  579.  
  580.  
  581. (**********************************************************************
  582.  * makenv: Create the environments for functions in a FIX.            *
  583.  **********************************************************************)
  584. fun makenv(initEnv,bindings: (lvar * lvar list * cexp) list,extraArgs) =
  585. let
  586.  
  587. (***>
  588.     fun COMMENT f = if !System.Control.CG.comment then (f(); ()) else ()
  589.     val _ = COMMENT(fn() => (pr "BEGINNING MAKENV.\nFunctions: ";
  590.                  ilist (map #1 bindings);
  591.                  pr "Initial environment:\n";
  592.                  printEnv initEnv; pr "\n"))
  593.  
  594.     val freevars =
  595.       (fn v => let val free = freevars v
  596.            in  COMMENT(fn() => (pr "Free in "; vp v; pr ":"; ilist free));
  597.            free
  598.            end)
  599. <***)
  600.  
  601. (* Separate function bindings into those that escape, those which are
  602.    known functions, and callee-save continuations. *)
  603.  
  604. val (escapeB,knownB) = partition (isEscape o #1) bindings
  605. val (calleeB,escapeB) = partition (isCallee o #1) escapeB
  606. val escapeV = uniq(map #1 escapeB)
  607. val calleeV = uniq(map #1 calleeB)
  608.  
  609. local val knownV = uniq(map #1 knownB)
  610.    in val knownlvar = member knownV
  611.   end
  612.  
  613. (***>
  614. val _ = COMMENT(fn() => (pr "Known functions:"; ilist (map #1 knownB)))
  615. <***)
  616.  
  617. (* Initial processing of the known function bindings. *)
  618. val knownB =
  619.  map (fn(v,args,body) =>
  620.         let val free = freevars v
  621.  
  622.             (* Separate the free variable list into known functions 
  623.              * defined in this FIX and other free variables. 
  624.              *)
  625.             val (fns,other) = partition knownlvar free
  626.          in ({v=v,args=args,body=body,other=other},length fns,fns)
  627.         end) knownB
  628.  
  629. (* Compute the closure of the call graph of the known functions. *)
  630. val knownB = closeCallGraph knownB
  631.  
  632. (* See which known functions require a closure, pass 1. *)
  633. local fun gatherNbrs l init =
  634.         fold (fn (({v,other,...}:info,_,_),free) =>
  635.           if member l v then merge(other,free)
  636.           else free) knownB init
  637. in
  638. val (knownB,fullClosure) = fold
  639.  (fn ((x as {args,other,...}:info,_,fns),(k,fullClosure)) =>
  640.   let
  641.       (* Get the combined list of free variables of all the functions
  642.          reachable in the call graph. *)
  643.       val free = gatherNbrs fns other
  644.       val len = length free
  645.  
  646.       (* Remove any escaping functions of the FIX from the free variable
  647.          list and mark that the function requires the closure. *)
  648.       local val free' = difference(free,escapeV)
  649.         val len' = length free'
  650.       in
  651.       val callc = (len<>len')
  652.       val free = free'
  653.       val len = len'
  654.       end
  655.  
  656.       (* Remove any callee-save continuations of the FIX from the free
  657.          variable list and mark that the function requires the continuation
  658.      extra arguments *)
  659.       local val free' = difference(free,calleeV)
  660.         val len' = length free'
  661.       in
  662.       val extrac = (len<>len')
  663.       val free = free'
  664.       val len = len'
  665.       end
  666.  
  667.       (* Replace known functions defined in other FIX'es by their free
  668.          variables, and callee-save continuation variables defined in
  669.      other FIX'es by their extra arguments. *)
  670.       val free = freeAnalysis(free,initEnv)
  671.  
  672.       (* If the free list contains two functions from the same
  673.          closure, we only need one pointer to the closure. *)
  674.       val free = sameClosureOpt(free,initEnv)
  675.  
  676.       (* If the function has too many extra arguments to fit into
  677.          registers, then we must put them in the closure. *)
  678.       val len = length free
  679.       val callc = callc orelse
  680.               ((length args + numCSregs + len >= maxfree)
  681.            andalso len > 1)
  682.  
  683.       (* for calleesave only *)
  684.       val callc = callc orelse extrac
  685.    in ((x,free,callc,fns)::k,fullClosure orelse extrac)
  686.   end) knownB (nil,false)
  687. end (* local *)
  688.  
  689. (* See which known functions require a closure, pass 2. *)
  690. local fun checkNbrs l init =
  691.         fold (fn (({v,...}:info,_,callc,_),c) =>
  692.             c orelse (callc andalso (member l v)))
  693.               knownB init
  694. in
  695. val (knownB,collected) = fold
  696.  (fn (({v,args,body,...}:info,free,callc,fns),(l,c)) =>
  697.    let val callc = checkNbrs fns callc
  698.        val (free,collected) = if callc then (nil,merge(free,c))
  699.                   else (free,c)
  700.        val label = Access.dupLvar v
  701.    in  ({v=v,args=args,body=body,free=free,label=label,
  702.      callc=callc}::l,collected)
  703.    end) knownB (nil,nil)
  704. end (* local *)
  705.  
  706.  
  707.  
  708. (***>
  709. val _ = COMMENT(fn() => (pr "Escaping functions:"; ilist (map #1 escapeB)))
  710. <***)
  711.  
  712. (* Get the combined list of the free variables of all the escaping functions
  713.    of the FIX. *)
  714. val escapeFree =
  715.  let val f = fold (fn (v,f') =>
  716.                  let val f'' = freevars v
  717.              in  merge(f'',f')
  718.              end)
  719.                       escapeV nil
  720.  in  remove(escapeV, f)
  721.  end
  722.  
  723. (* Decide on labels for the escaping functions. *)
  724. val escapeB = map (fn (v,a,b) => (v,Access.dupLvar v,a,b)) escapeB
  725.  
  726. (* Replace knownfuncs defined in this FIX with their free variables. *)
  727. local val (fns,other) = partition knownlvar escapeFree
  728. in
  729. val escapeFree : lvar list =
  730.   fold (fn ({v,free,...},b) =>
  731.     if member fns v
  732.         then merge(free,b)
  733.     else b)
  734.   knownB other
  735. end (* local *)
  736.  
  737. (* Remove callee-save continuations defined in this FIX, and mark that
  738.  * the closure should contain all free variables of the continuations. 
  739.  *)
  740. local val contlvar = member calleeV
  741. in
  742. val fullClosure = fullClosure orelse (exists contlvar escapeFree)
  743. val escapeFree = difference(escapeFree,calleeV)
  744. end (* local *)
  745.  
  746. (* Add the free variables of knownfuncs in this FIX which were spilled into
  747.  * the closure. 
  748.  *)
  749. val escapeFree = merge(collected,escapeFree)
  750.  
  751. (* Replace knownfuncs defined elsewhere with their free variables, 
  752.  * and escaping functions defined elsewhere with their closures, and 
  753.  * callee-save continuations with their extra arguments. 
  754.  *)
  755. val escapeFree : lvar list =
  756.   let val escapeFree = freeAnalysis(escapeFree,initEnv)
  757.       val escapeFree = sameClosureOpt(escapeFree,initEnv)
  758.   in  escapeFree
  759.   end
  760.  
  761.  
  762. (***>
  763. val _ = COMMENT(fn() => (pr "Callee-save continuations:";
  764.                          ilist (map #1 calleeB)))
  765. <***)
  766.  
  767. (* Get the combined list of the free variables of all the callee-save
  768.  * continuations of the FIX. 
  769.  *)
  770. val calleeFree : lvar list =
  771.  let val f = fold (fn (v,f') =>
  772.            let val f'' = freevars v
  773.            in  merge(f'',f')
  774.            end)
  775.                   calleeV nil
  776.  in  remove(escapeV,remove(calleeV,f))
  777.  end
  778.  
  779. (* Decide on labels for the callee-save continuations. *)
  780. val calleeB = map (fn (v,a,b) => (v,Access.dupLvar v,a,b)) calleeB
  781.  
  782. (* Replace knownfuncs defined in this FIX with their free variables. *)
  783. val calleeFree : lvar list =
  784.   let val (fns,other) = partition knownlvar calleeFree
  785.   in  fold (fn ({v,free,...},b) =>
  786.         if member fns v
  787.         then merge(free,b)
  788.         else b) knownB other
  789.   end
  790.  
  791. val calleeFree : lvar list =
  792.   let val calleeFree = freeAnalysis(calleeFree,initEnv)
  793.       val calleeFree = sameClosureOpt(calleeFree,initEnv)
  794.   in  calleeFree
  795.   end
  796.  
  797.  
  798. (**********************************************************************
  799.  * CALLEE-SAVE REGISTER TARGETING                                     *
  800.  **********************************************************************)
  801. local
  802. (** TJ comments are delimited (** ... **). **)
  803.  
  804. (** There is a problem with closures and aliasing: each function in the
  805.     closure is a name for the closure.  This has some effect on all the
  806.     following functions. **)
  807.  
  808. fun in'(v,nil) = false
  809.   | in'(v:int,hd::tl) = if v = hd then true else in'(v,tl)
  810.  
  811. (* Look through a list of enclosing closures to see if we can use them.
  812.  *    retract : lvar list * ((lvar * (lvar * object)) list) -> lvar list 
  813.  *)
  814. fun retract(fl,cl) = (* fl = free list, cl = closure list *)
  815.   let (** How many of fl are reached from the closure? **)
  816.       fun weight (x as (v,_)) =
  817.         let val t = sublist (inClosure x) fl
  818.         in  (** Return how many, which ones, and the closure **)
  819.         (length t,t,v)
  820.         end
  821.  
  822.       (** The closures that reach at least one from fl **)
  823.       val clinfo = sublist (fn (k,_,_) => (k > 0)) (map weight cl)
  824.  
  825.       (** The closures that reach at least 4 from fl,
  826.           OR that are in fl themselves.
  827.           Makes the previous filter bogus -- might as well eliminate it.
  828.       These closures might still reach values that are not in fl,
  829.       so in general it is NOT safe for space to use them. **)
  830.       val clinfo = sublist (fn (k,_,v) => (k > 3) orelse (in'(v,fl))) clinfo
  831.  
  832.       (** Sort the closures by their usefulness.  Unfortunately, this
  833.           sorts into REVERSE order, i.e. the least useful appear at the
  834.           front of the returned list. **)
  835.       val op btr = fn ((k1,_,_),(k2,_,_)) => (k1 > (k2 : int))
  836.       val clinfo = (Sort.sort op btr) clinfo
  837.  
  838.       (** Consider each closure in turn.  If it looks like it will help
  839.           us, subtract the reachable elements from fl and add the
  840.       closure itself. **)
  841.       fun repclos (fl,nil) = fl
  842.         | repclos (fl,(_,t,v)::tl) = 
  843.              let val t' = sublist (fn x => in'(x,fl)) t
  844.          in if ((length(t')) > 3) orelse in'(v,fl)
  845.                 then repclos(enter(v,difference (fl,t')),tl)
  846.                 else repclos(fl,tl)
  847.              end
  848.    in repclos(fl,clinfo)
  849.   end
  850.  
  851. val method = 0 (* or !System.Control.CG.misc3 *)
  852.  
  853. local
  854. (** If a non-closure free variable is reachable from a closure free variable,
  855.     don't bother to include it in the new closure. **)
  856. fun thinner(fl,cl) =
  857.   let val clinfo = sublist (fn (v,_) => in'(v,fl)) cl
  858.  
  859.       (** inClinfo(x) iff x is reachable from clinfo. **)
  860.       fun inClinfo z =
  861.          let fun inl nil = false
  862.                | inl (hd::tl) = (inClosure hd z) orelse inl tl
  863.          in  inl clinfo
  864.          end
  865.   in  (** clinfo plus elements of fl not reachable from clinfo. **)
  866.       (merge(uniq(map #1 clinfo),sublist (not o inClinfo) fl))
  867.   end
  868. in
  869. (** NOT safe for space unless all of the cl can be included safely
  870.     (see filter0 in calleealloc). **)
  871. fun preproc(fl,cl) = 
  872.   let val m = length(fl)
  873.       (** inImmedAll(v,e) iff all of fl is reachable from e **)
  874.       fun inImmedAll x =
  875.           (m = length(sublist (inClosure x) fl))
  876.       (** If all of the free variables are reachable from a single closure,
  877.           just use that one.  Otherwise, do thinner or retract. **)
  878.       fun h nil = if method <> 2 then thinner(fl,cl) else retract(fl,cl)
  879.         | h ((x as (v,_))::tl) = if inImmedAll x then [v] else h(tl)
  880.    in h cl
  881.   end 
  882. end (* local *)
  883.  
  884. (** NOT safe for space unless all of the cl can be included safely
  885.     (see filter0 in calleealloc). **)
  886. (** newfl = list of free variables,
  887.     cl = list of closures,
  888.     k = a threshold value **)
  889. fun preproc2(newfl,cl,k) = 
  890.   let (** how many of newfl are reachable from a closure? **)
  891.       fun weight (x as (v,_)) =
  892.         let val t = sublist (inClosure x) newfl
  893.     in  (** Return how many, which ones, and the closure. **)
  894.         (length t,t,v)
  895.         end
  896.       val m = length(newfl)
  897.  
  898.       (** The closures that reach at least one from newfl. **)
  899.       (** In fact we only consider cases where k > 1, might as well
  900.          filter out k=1 here. **)
  901.       val clinfo = sublist (fn (k,_,_) => (k>0))  (map weight cl)
  902.  
  903.       (** Sort the closures by their usefulness.  Unfortunately, this
  904.           sorts into REVERSE order, i.e. the least useful appear at the
  905.           front of the returned list.  Also, we only care about the
  906.       MOST useful one, ought to be doing an O(n) max operation
  907.       instead of a sort. **)
  908.       val op btr = fn ((k1,_,_),(k2,_,_)) => (k1 > (k2 : int))
  909.       val clinfo = (Sort.sort op btr) clinfo
  910.  
  911.    in case clinfo of 
  912.         nil => (** None of the free variables appear in closures. **)
  913.         (newfl,NONE)
  914.       | (j,t,v)::_ =>
  915.         (let (** Do we bring the number of free variables below
  916.              the threshold? **)
  917.          val doit = ((j > 1) andalso ((m - j) <= k))
  918.  
  919.          (** Or do we save a lot?  Note that this is NOT safe
  920.              for space, as dead variables might be reachable
  921.              from the closure. **)
  922.          val doit = doit orelse (j > (m div 2) + 1)
  923.  
  924.          (** And finally, were we also over the threshold to
  925.              begin with? **)
  926.          val doit = doit andalso (m > k+1)
  927.  
  928.          in  (** Decide whether to use the closure or not. **)
  929.          if doit then (difference(newfl,t),SOME v)
  930.          else (newfl,NONE)
  931.          end )
  932.   end
  933.  
  934.  
  935. in (* body of local *)      
  936.    
  937. (* Try to see if there are any closures already made in the environment which
  938.  * could dramatically decrease the size of current closures.
  939.  * shorten : lvar list -> lvar list
  940.  *)
  941. fun shorten(fl) =
  942.  (case fl
  943.     of nil => nil 
  944.      | _ => (if method <> 2 then fl
  945.          else if length(fl) < 4 then fl
  946.          else retract(fl,getClosures initEnv)))
  947.  
  948.  
  949. (* Given a list of free variables, if k = 0 we use aggressive approach, if 
  950.  * k = numCSregs -1, we use diligent (or lazy) approach. However when EB 
  951.  * is false, we'll use conservative approach anyway.
  952.  *) 
  953. fun calleealloc(fl,k) =
  954.   let
  955.  
  956. (***>
  957.       val _ = COMMENT(fn () => (pr "Calleealloc:"; ilist fl))
  958. <***)
  959.  
  960.       (* this piece of code is used to stop unsafe closure sharing used 
  961.        * among embedied continuation functions. closlist is re-filtered
  962.        * by the free variable list fl.
  963.        *)
  964.       (** Consider only closures which do not hold on to dead values.
  965.           This version is overly restrictive: every single element
  966.       of the closure must be free.  If the closure has two functions,
  967.       both must be in the free list; in fact both will never be in
  968.       the free list if we have already passed the free list through
  969.       sameClosureOpt -- and this is always the case with the fl passed
  970.       to calleealloc.  A similar remark applies if one of the contents
  971.       is a closure. **)
  972.       val closlist = getClosures initEnv
  973.       fun filter0 (v,CR(_,{functions,values,closures,...})) =
  974.     let val functions = map #1 functions
  975.         val closures = map #1 closures
  976.         val t1 = uniq(functions @ values @ closures)
  977.         in  fold (fn (x,b) => (in'(x,fl) andalso b)) t1 true
  978.         end
  979.       val closlist = sublist filter0 closlist 
  980.  
  981.       val restm = sublist (fn x => in'(x,fl)) extraArgs
  982.       val rest = if (length restm) = numCSregs then (tl restm)
  983.                  else restm
  984.       exception FAIL of lvar list * int
  985.       fun first(nil,0,res) = res
  986.         | first(nil,k,res) = raise FAIL (res,k)
  987.         | first(_,0,res) = res
  988.         | first(hd::tl,k,res) = first(tl,k-1,res@[hd])
  989.       and first0(wl,vl,k) = first(wl,k,nil) handle FAIL (c,i) => 
  990.                                (first(vl,i,c) handle FAIL (res,_) => res)
  991.  
  992.       (** Take two lists, and return a list of length equal to the longer
  993.           of the two lists.  The i^th element of the list will be the
  994.           i^th element of the first list, or the i^th element of the second
  995.       list if the first list isn't long enough. **)
  996.       fun punch(nil,nil) = nil
  997.         | punch(nil,tl) = tl 
  998.         | punch(tl,nil) = tl
  999.         | punch(hd1::tl1,hd2::tl2) = hd1::punch(tl1,tl2)
  1000.  
  1001.       (* Test if it's the innermost continuation function. *)
  1002.       fun bmerge((x,xl),(y,yl)) = ((x orelse y),merge(xl,yl))
  1003.  
  1004.     (** the getv function may be modified by doing more data flow analysis **)
  1005.     (* Choose k lvars from vl, default is rest *)
  1006.       fun getv(vl,k,rest) = 
  1007.          if length(vl) <= k then punch(vl,rest)
  1008.          else (let val el = (map (ebinfo o (fn (v,_,_,_) => v)) calleeB)
  1009.                    val (EB,ncand) = fold bmerge el (false,nil)
  1010.                 in if (not EB) then  (* leaf cont nodes *)
  1011.                        punch (rest,first0(difference(vl,uniq rest),nil,k))
  1012.                    else (let val wl = difference(vl,ncand)
  1013.                              val ul = difference(vl,wl)
  1014.                           in punch (first0(wl,ul,k),rest)
  1015.                          end)
  1016.            end)
  1017.    in if k=0                      
  1018.       then (preproc(fl,closlist),rest)
  1019.       else (let val newfl = preproc(fl,closlist) 
  1020.              in if length(newfl) <= 1 then (newfl,rest)
  1021.                 else case preproc2(newfl,closlist,k) of 
  1022.                        (vl,NONE) => 
  1023.                          (let val t = length(vl)
  1024.                               val cand = if t <= (k+1) 
  1025.                                          then tl(punch(vl,restm))
  1026.                                          else getv(vl,k,rest)
  1027.                            in (difference(vl,uniq cand),cand)
  1028.                           end)
  1029.                      | (vl,SOME v) => 
  1030.                          (if length(vl) <= k then 
  1031.                               ([v],getv(vl,k,rest))
  1032.                           else 
  1033.                             (let val rest0 = if length(rest) = k 
  1034.                                              then (tl rest)
  1035.                          else rest
  1036.                                  val cand = getv(vl,k-1,rest0)
  1037.                                  val result0 = difference(vl,uniq cand)
  1038.                               in (result0,v::cand)
  1039.                              end))
  1040.             end)
  1041.   end (* calleealloc *)         
  1042. end (* local *)
  1043.  
  1044.  
  1045. (* Decide which variables go into the closure and which variables go
  1046.    into callee-save registers. *)
  1047. val (escapeFree,rest) = case (calleeB,escapeB,collected) 
  1048.     of (nil,_,_) =>  (shorten(escapeFree),nil)
  1049.      | (_,nil,nil) =>
  1050.         if fullClosure
  1051.         then calleealloc(calleeFree,0)
  1052.         else calleealloc(calleeFree,numCSregs-1)
  1053.      | (_,nil,_) =>
  1054.     let val left = difference(calleeFree,escapeFree)
  1055.         val (nfl,rest) = if fullClosure
  1056.                  then calleealloc(left,0)
  1057.                  else calleealloc(left,numCSregs-1)
  1058.     in (merge(escapeFree,nfl),rest)
  1059.     end
  1060.      | _ => (let val fl = merge(escapeFree,calleeFree)
  1061.               in calleealloc(fl,0)
  1062.              end) 
  1063.  
  1064. (***>
  1065. val _ = COMMENT(fn () =>
  1066.         (pr "Free variables to be accessible from the closure:";
  1067.      ilist escapeFree;
  1068.      pr "Free variables to be accessible from callee-save arguments:";
  1069.      ilist rest))
  1070. <***)
  1071.  
  1072. (* Given the functions to be defined in the closure (from escapeB), the free
  1073.    variables which should be contained in the closure (escapeFree), and their
  1074.    current locations (initEnv), decide on a closure representation. *)
  1075. val (closureInfo,calleeReg1) = 
  1076.       case (escapeB,escapeFree)
  1077.        of (nil,nil) => (NONE,NONE)
  1078.         | (nil,[v]) => (NONE,SOME v)
  1079.         | _ => 
  1080.           (let val escapeB' = map (fn(v,l,_,_) => (v,l)) escapeB
  1081.                val (cname,clos) = closureStrategy(escapeB',escapeFree,initEnv)
  1082.             in (SOME clos, SOME cname)
  1083.            end)
  1084.  
  1085. val rest = case calleeReg1 of NONE => rest
  1086.                             | SOME cname => (cname::rest)
  1087.  
  1088. (* Add new known function information to the environment. *)
  1089. local fun addF(v,label,free) = augment((v,Function{label=label,free=free}),
  1090.                        baseEnv)
  1091. in
  1092. val _ = app
  1093.  (case calleeReg1
  1094.     of NONE =>
  1095.     (fn{v,free,callc,label,...} =>
  1096.       if callc then error "29488 in closure"
  1097.       else addF(v,label,free))
  1098.      | SOME cname =>
  1099.     (fn{v,free,callc,label,...} =>
  1100.       if callc
  1101.       then addF(v,label,enter(cname,free))
  1102.       else addF(v,label,free)))
  1103.  knownB
  1104. end (* local *)
  1105.  
  1106.  
  1107. (* Final construction of the environment for each standard function. *)
  1108. val escapeFrags : (lvar * lvar list * cexp * env * lvar list) list =
  1109.  (case (escapeB,closureInfo)
  1110.     of (nil,_) => nil
  1111.      | (_,NONE) => error "unexpected 23422 in closure"
  1112.      | (_,SOME{cr,...}) => 
  1113.       let val env1 = baseEnv
  1114.           fun f ((v,l,args,body),i) =
  1115.         let val myCname = v
  1116.             val env = offset(i,cr,myCname,env1)
  1117.             val (args,kl) = addExtra(args)
  1118.             val env = fold augmentV args env
  1119. (***>
  1120.             val _ = COMMENT(fn () => (pr "\nEnvironment in escaping ";
  1121.                           vp v; pr ":\n";
  1122.                           printEnv env))
  1123. <***)
  1124.         in  inc System.Control.CG.escapeGen;
  1125.             (l,mkLvar()::myCname::args,body,env,kl)
  1126.         end
  1127.       in  formap f escapeB
  1128.       end)
  1129.  
  1130.  
  1131. (* Final construction of the environment for each known function. *)
  1132. val knownFrags : (lvar * lvar list * cexp * env * lvar list) list =
  1133.  map (fn{v,args,body,free,label,callc} =>
  1134.   let fun addv(v,env) = case whatIs(initEnv,v)
  1135.              of (Function _) => error "cps/closure.223"
  1136.               | obj => augment((v,obj),env)
  1137.  
  1138.       val (free',env) =
  1139.         case (callc,calleeReg1)
  1140.       of (false,_) =>
  1141.             (inc System.Control.CG.knownGen;
  1142.          (free,baseEnv))
  1143.        | (true,NONE) => error "unexpected ~4 in closure"
  1144.        | (true,SOME v) =>
  1145.                (let val env' = case closureInfo
  1146.                       of NONE => addv(v,baseEnv)
  1147.                        | SOME{cname,cr,...} => 
  1148.                             augment((cname,Closure cr),baseEnv)
  1149.                  in (inc CGoptions.knownClGen; 
  1150.                      (enter(v,free),env'))
  1151.                 end) 
  1152.  
  1153.       val env = fold addv free env
  1154.       val (args,extra) = addExtra(args)
  1155.       val env = fold augmentV args env
  1156.  
  1157. (***>
  1158.       val _ = COMMENT(fn () => (pr "\nEnvironment in known ";
  1159.                             vp v; pr ":\n";
  1160.                 printEnv env))
  1161. <***)
  1162.  
  1163.       val args = args @ free'
  1164.   in  if extra = nil then (label,args,body,env,extraArgs)
  1165.       else (label,args,body,env,extra)
  1166.   end)
  1167.  knownB
  1168.  
  1169. (* Final construction of the environment for each callee-save
  1170.    continuation. *)
  1171. val calleeFrags : (lvar * lvar list * cexp * env * lvar list) list =
  1172.   case calleeB
  1173.     of nil => nil
  1174.      | _ => 
  1175.     (let val rest =
  1176.        let (** The variables already in the calleesave arguments. **)
  1177.            val wl = extraArgs
  1178.            (** The new values to put in the calleesave arguments. **)
  1179.            val wl' = uniq wl
  1180.            val left = sublist (fn x => not (member wl' x)) rest
  1181.            val vl = uniq rest
  1182.            (** A first assigment of calleesave arguments -- if the
  1183.            position is already occupied by something we need,
  1184.            leave it there (SOME case) otherwise mark that it
  1185.            is free to be filled (NONE case). **)
  1186.            val base =
  1187.                  let fun g(x::tl,vl) = 
  1188.                             if member vl x then ((SOME x)::g(tl,rmv(x,vl)))
  1189.                             else (NONE::g(tl,vl))
  1190.                        | g(nil,vl) = nil
  1191.                   in g(wl,vl)
  1192.                  end
  1193.            (** Fill in the holes in the calleesave argument template with
  1194.            the new values.  **)
  1195.            fun h(tl,nil) = tl
  1196.                  | h((SOME x)::tl,ul) = (SOME x)::h(tl,ul)
  1197.          | h(NONE::tl,u::ul) = (SOME u)::h(tl,ul)
  1198.          | h _ = error "errors in closure1.sml --- rest/h"
  1199.        in  h(base,left)
  1200.        end
  1201.  
  1202.      (** Only used in extramap. **)
  1203.      fun getenv (SOME x) = 
  1204.                 ((case whatIs(initEnv,x) of 
  1205.               (Function _) => error "cps/closure437"
  1206.             | obj => (VAR x,obj))
  1207.                  handle Lookup(tt,ee) =>
  1208.                    (case closureInfo of 
  1209.                        NONE => (raise (Lookup(tt,ee)))
  1210.                      | SOME{cname,cr,...} =>
  1211.                         (if (cname=x) then (VAR cname, Closure cr)
  1212.                          else raise (Lookup(tt,ee)))))
  1213.        | getenv NONE = (INT 0,Value)
  1214.  
  1215.          val extramap = if numCSregs = 0 then nil
  1216.                         else (map getenv rest)
  1217.  
  1218.      val _ = app (fn (v,l,a,b) => addinc(v,l,map #1 extramap)) calleeB
  1219.  
  1220.      val extraenv = map (fn (VAR x,c) => (x,c)
  1221.                               | (_,l) => (mkLvar(),Value))
  1222.                         extramap
  1223.      val env = baseEnv
  1224.      val env = fold augment extraenv env
  1225.  
  1226.      fun f (v,l,args,body) =
  1227.        let val env = fold augmentV args env
  1228.            val args' = mkLvar()::args@(map #1 extraenv)
  1229. (***>
  1230.            val _ = COMMENT(fn () =>
  1231.                    (pr "\nEnvironment in callee-save continuation ";
  1232.                 vp v; pr ":\n";
  1233.                 printEnv env))
  1234. <***)
  1235.        in  inc CGoptions.calleeGen;
  1236.            (l,args',body,env,map #1 extraenv)
  1237.        end
  1238.      in  map f calleeB
  1239.      end)
  1240.             
  1241.  
  1242. fun mkrexp(contents,cname) =
  1243.   if not(!CGoptions.allocprof) then 
  1244.                      fn ce => RECORD(RK_RECORD,contents,cname,ce)
  1245.   else let val prof =
  1246.          case (escapeB,knownB,calleeB)
  1247.                of (nil,_,nil) => profKClosure
  1248.             | (nil,_,_) => profCClosure
  1249.         | _ => profClosure
  1250.        in  prof(length contents) o (fn ce => 
  1251.                                       RECORD(RK_RECORD,contents,cname,ce))
  1252.        end
  1253.  
  1254. val frags = escapeFrags@knownFrags@calleeFrags
  1255. val env = initEnv
  1256.  
  1257. val (rexp,env) =
  1258.  (case closureInfo
  1259.     of NONE => ((fn x => x),env)
  1260.      | SOME{cname,cr,contents} => 
  1261.       let val (contents,header) =
  1262.                 recordEl(map (fn v => (v, OFFp0)) contents, env)
  1263.           val env = augment((cname,Closure cr),env)
  1264.       in  (header o mkrexp(contents,cname),env)
  1265.       end)
  1266.  
  1267. in  (* body of makenv *)
  1268. (***>
  1269.           COMMENT(fn () => (pr "\nEnvironment after FIX:\n";
  1270.                             printEnv env; pr "MAKENV DONE.\n\n"));
  1271. <***)
  1272.     (rexp,frags,env)
  1273. end (* makenv *)
  1274.  
  1275.  
  1276. (**********************************************************************
  1277.  * close0: MAIN LOOP of closeCPS                                      *
  1278.  **********************************************************************)
  1279. fun close0(ce,env,extraArgs) =
  1280. let
  1281. fun close1(f,vl,ce,env,eA') =
  1282.   ((f,vl,close0(ce,env,eA'))
  1283.    handle Lookup(v,env) => (pr "LOOKUP FAILS on "; vp v;
  1284.                 pr "\nin environment:\n";
  1285.                 printEnv env;
  1286.                 pr "\nin function:\n";
  1287.                 CPSprint.showfun pr (f,vl,ce);
  1288.                 error "Lookup failure in cps/closure.sml"))
  1289. fun close(ce,env) =
  1290.   case ce
  1291.     of FIX(bindings,b) =>
  1292.         let val (header,frags,env') = makenv(env,bindings,extraArgs)
  1293.     in  FIX(map close1 frags, header(close(b,env')))
  1294.     end
  1295.      | APP(f,args) =>
  1296.         let val obj = (case f of VAR v => whatIs(env,v) | _ => Value)
  1297.     in  case obj
  1298.           of Closure(CR(offset,{functions,...})) =>
  1299.            let val (env,h) = fixAccess([f],env)
  1300.                val (args',_,h') = fixArgs(args,env)
  1301.                val (_,label) = nth(functions,offset)
  1302.                val call = APP(LABEL label,LABEL label::f::args')
  1303.            in  if not(!CGoptions.allocprof)
  1304.                then h(h'(call))
  1305.                else h(h'(case args
  1306.                    of [_] => profCntkCall call
  1307.                     | _ => profStdkCall call))
  1308.            end
  1309.            | Function{label,free} =>
  1310.            let (* NOTE: 0 or 1 arg will be a continuation --
  1311.               0 if f is a known continuation. *)
  1312.                val (args',_,header) = fixArgs(args@(map VAR free),env)
  1313.                val call = APP(LABEL label,args')
  1314.            in  if not(!CGoptions.allocprof)
  1315.                then header call
  1316.                else header(profKnownCall call)
  1317.            end
  1318.            | Callee(label,extra) =>
  1319.            let val args' = args@extra
  1320.                val (env,header) = fixAccess(label::args',env)
  1321.                val call = APP(label,label::args')
  1322.            in  if not(!CGoptions.allocprof)
  1323.                then header call
  1324.                else header(case label
  1325.                          of LABEL _ => profCSCntkCall call
  1326.                                   | _ => profCSCntCall call)
  1327.            end
  1328.            | Value =>
  1329.                    let (* Ugly hack to handle functions introduced by
  1330.               contmap for strange continuation variables. *)
  1331.                val args' = case args
  1332.                      of [_,INT 0] => args@extraConst
  1333.                       | [_,INT _] => error "29 closure"
  1334.                       | _ => args
  1335.                val (env,h) = fixAccess([f],env)
  1336.                val (args',_,h') = fixArgs(args',env)
  1337.                val l = mkLvar()
  1338.                val call = SELECT(0,f,l,(APP(VAR l,(VAR l)::f::args')))
  1339.            in  if not(!CGoptions.allocprof)
  1340.                then h(h'(call))
  1341.                else h(h'(case args
  1342.                    of [_] => profCntCall call
  1343.                     | _ =>  profStdCall call))
  1344.            end
  1345.     end
  1346.      | SWITCH(v,c,l) =>
  1347.     let val (env,header) = fixAccess([v],env)
  1348.     in  header (SWITCH(v,c,map (fn c => close(c,env)) l))
  1349.     end
  1350.      | RECORD(k,l,v,c) =>
  1351.     let val (l,header) = recordEl(l,env)
  1352.         val record = RECORD(k,l,v,close(c,augmentV(v,env)))
  1353.     in  if not(!CGoptions.allocprof)
  1354.         then header record
  1355.         else header(profRecord (length l) record)
  1356.     end
  1357.      | SELECT(i,v,w,c) =>
  1358.         let val (env,header) = fixAccess([v],env)
  1359.     in  header(SELECT(i,v,w,close(c,augmentV(w,env))))
  1360.     end
  1361.      | OFFSET(i,v,w,c) => error "OFFSET in cps/closure.sml!"
  1362.      | BRANCH(i,args,c,e1,e2) =>
  1363.     let val (env,header) = fixAccess(args,env)
  1364.     in  header (BRANCH(i,args,c,close(e1,env),close(e2,env)))
  1365.     end
  1366.      | SETTER(i,args,e) =>
  1367.     let val (env,header) = fixAccess(args,env)
  1368.     in  header (SETTER(i,args,close(e,env)))
  1369.     end
  1370.      | LOOKER(i,args,w,e) =>
  1371.     let val (env,header) = fixAccess(args,env)
  1372.     in  header (LOOKER(i,args,w,close(e,augmentV(w,env))))
  1373.     end
  1374.      | ARITH(i,args,w,e) =>
  1375.     let val (env,header) = fixAccess(args,env)
  1376.     in  header (ARITH(i,args,w,close(e,augmentV(w,env))))
  1377.     end
  1378.      | PURE(i,args,w,e) =>
  1379.     let val (env,header) = fixAccess(args,env)
  1380.     in  header (PURE(i,args,w,close(e,augmentV(w,env))))
  1381.     end
  1382. in  (* body of close0 *)
  1383.     close(ce,env)
  1384. end
  1385.  
  1386. val (vl,e) = addExtra(vl)
  1387. val env1 = fold augmentV (f::vl) baseEnv
  1388.  
  1389. in  (* body of closeCPS *)
  1390.     (mkLvar(),mkLvar()::f::vl,unrebind(close0(ce,env1,e)))
  1391. end
  1392.  
  1393. end (* structure Closure *)
  1394.  
  1395.